package com.fub.view.mapcomponents;

import java.util.ArrayList;
import java.util.List;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;

import com.fub.guidance.Edge;
import com.fub.guidance.Graph;
import com.fub.guidance.Point;
import com.fub.guidance.Vertex;
import com.fub.guidance.Wall;
import com.fub.util.PreferenceDAO;
import com.fub.util.Util;

public class WallComponent {

	private Wall wall;
	private int wallHeight;
	private Canvas canvas;
	private Paint paintWall;
	private Paint paintWall3D;
	private Paint paintWall3DFILL;
	private Paint paintWall3DDoor;
	private Paint paintDoor;
	private Point fromOnDisplay;
	private Point toOnDisplay;
	private PreferenceDAO preferenceDAO;
	private Graph graph;
	private List<Point> doors;
	private Paint paintWeight;

	public WallComponent(Wall wall, PreferenceDAO preferenceDAO) {
		this.wall = wall;
		this.preferenceDAO = preferenceDAO;
		this.doors = new ArrayList<Point>();
		this.graph = Graph.getInstance();
		initPaints();
		try {
			testIntersection();
		} catch (IllegalArgumentException e) {

		}
	}

	public Wall getWall() {
		return this.wall;
	}

	public Point intersection(int x1, int y1, int x2, int y2, int x3, int y3,
			int x4, int y4) {
		int d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
		if (d == 0)
			return null;

		int xi = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2)
				* (x3 * y4 - y3 * x4))
				/ d;
		int yi = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2)
				* (x3 * y4 - y3 * x4))
				/ d;

		if (xi < Math.min(x1, x2) || xi > Math.max(x1, x2)) {
			return null;
		}
		if ((xi < Math.min(x3, x4))) {
			return null;
		}
		int max = Math.max(x3, x4);
		if (xi > max) {
			return null;
		}
		return new Point(xi, yi, 0);
	}

	private void testIntersection() {
		for (Edge edge : this.graph.getEdges()) {

			Vertex from = this.graph.getNodeById(edge.getSourceId());
			if (from.getPosition().getZ() != this.wall.getZ()) {
				continue;
			}
			Vertex to = this.graph.getNodeById(edge.getDestinationId());

			int x1 = from.getPosition().getX();
			int y1 = from.getPosition().getY();
			int x2 = to.getPosition().getX();
			int y2 = to.getPosition().getY();

			int x3 = this.wall.getX1();
			int y3 = this.wall.getY1();

			int x4 = this.wall.getX2();
			int y4 = this.wall.getY2();

			Point intersection = intersection(x1, y1, x2, y2, x3, y3, x4, y4);

			if (intersection != null) {
				this.doors.add(new Point((int) intersection.getX(),
						(int) intersection.getY(), 0));
			}
		}
	}

	private void initPaints() {
		this.paintWall = new Paint(Paint.ANTI_ALIAS_FLAG);
		this.paintWall.setStyle(Paint.Style.STROKE);
		this.paintWall.setColor(Color.argb(40, 0, 0, 0));
		this.paintWall.setStrokeWidth(2);
		this.paintWall3D = new Paint(Paint.ANTI_ALIAS_FLAG);
		this.paintWall3D.setStyle(Paint.Style.STROKE);
		this.paintWall3D.setColor(Color.argb(40, 0, 0, 0));
		this.paintWall3D.setStrokeWidth(1);
		this.paintWall3DFILL = new Paint(Paint.ANTI_ALIAS_FLAG);
		this.paintWall3DFILL.setStyle(Paint.Style.FILL);
		this.paintWall3DFILL.setColor(Color.argb(50, 0, 0, 0));
		this.paintWall3DDoor = new Paint(Paint.ANTI_ALIAS_FLAG);
		this.paintWall3DDoor.setStyle(Paint.Style.FILL);
		this.paintWall3DDoor.setColor(Color.argb(50, 0, 0, 0));
		this.paintDoor = new Paint();
		this.paintDoor.setStyle(Style.FILL);
		this.paintDoor.setColor(Color.RED);
	}

	public void draw(Canvas canvas) {
		if (this.preferenceDAO.isFingerprintEnabled()) {
			this.wallHeight = 0;
		} else {
			this.wallHeight = (int) (this.preferenceDAO.getZoomFactor() * 20);
		}
		this.canvas = canvas;
		this.fromOnDisplay = new Point(
				(int) (this.wall.getPositonFrom().getX() * this.preferenceDAO
						.getZoomFactor()),
				(int) (this.wall.getPositonFrom().getY() * this.preferenceDAO
						.getZoomFactor()), this.wall.getPositonFrom().getZ());
		this.toOnDisplay = new Point(
				(int) (this.wall.getPositionTo().getX() * this.preferenceDAO
						.getZoomFactor()),
				(int) (this.wall.getPositionTo().getY() * this.preferenceDAO
						.getZoomFactor()), this.wall.getPositionTo().getZ());
		drawWall(0);
		drawWall(this.wallHeight);
		drawWallLink(this.wallHeight);
		drawWallFill();
	}

	private void drawWall(int height) {

		Path p = new Path();
		p.moveTo(this.fromOnDisplay.getX(), this.fromOnDisplay.getY() - height);
		p.lineTo(this.toOnDisplay.getX(), this.toOnDisplay.getY() - height);
		this.canvas.drawPath(p, this.paintWall);

		this.paintWeight = new Paint();
		this.paintWeight.setAntiAlias(true);
		this.paintWeight.setTextSize(10);
		this.paintWeight.setColor(Color.BLACK);
	}

	private void drawWallLink(int height) {
		Path s = new Path();
		s.moveTo(this.fromOnDisplay.getX(), this.fromOnDisplay.getY());
		s.lineTo(this.fromOnDisplay.getX(), this.fromOnDisplay.getY() - height);
		this.canvas.drawPath(s, this.paintWall3D);
	}

	private void drawWallFill() {
		Path p = new Path();
		int doorHalfWidht = (int) (4 * this.preferenceDAO.getZoomFactor());
		Point doorLeftBottom;
		Point doorRightBottom;
		Point doorLeftTop;
		Point doorRightTop;
		p.moveTo(this.fromOnDisplay.getX(), this.fromOnDisplay.getY());

		Point toOnDisplay2 = this.toOnDisplay;
		for (Point doorPos : this.doors) {
			Point zoomedDoorPos = Util.calculateZoomedPosition(doorPos,
					this.preferenceDAO);
			int[] doorLeftline = { zoomedDoorPos.getX() - doorHalfWidht,
					zoomedDoorPos.getY() + 100,
					zoomedDoorPos.getX() - doorHalfWidht,
					zoomedDoorPos.getY() - 100 };
			int[] doorRightLine = { zoomedDoorPos.getX() + doorHalfWidht,
					zoomedDoorPos.getY() + 100,
					zoomedDoorPos.getX() + doorHalfWidht,
					zoomedDoorPos.getY() - 100 };

			Point leftDoorIntersection = intersection(this.fromOnDisplay.getX(),
					this.fromOnDisplay.getY(), toOnDisplay2.getX(),
					toOnDisplay2.getY(), doorLeftline[0], doorLeftline[1],
					doorLeftline[2], doorLeftline[3]);

			Point rightDoorIntersection = intersection(this.fromOnDisplay.getX(),
 this.fromOnDisplay.getY(), toOnDisplay2.getX(),
					toOnDisplay2.getY(), doorRightLine[0], doorRightLine[1],
					doorRightLine[2], doorRightLine[3]);

			if (leftDoorIntersection == null || rightDoorIntersection == null)
				return;

			int doorHeigh = (int) (this.wallHeight / 1.5f);

			if (Math.abs(leftDoorIntersection.getX() - this.fromOnDisplay.getX()) < Math
					.abs(rightDoorIntersection.getX() - this.fromOnDisplay.getX())) {
				doorLeftBottom = leftDoorIntersection;
				doorRightBottom = rightDoorIntersection;
				doorLeftTop = new Point(leftDoorIntersection.getX(),
						leftDoorIntersection.getY() - doorHeigh, 0);
				doorRightTop = new Point(rightDoorIntersection.getX(),
						rightDoorIntersection.getY() - doorHeigh, 0);
			} else {
				doorRightBottom = leftDoorIntersection;
				doorLeftBottom = rightDoorIntersection;
				doorRightTop = new Point(leftDoorIntersection.getX(),
						leftDoorIntersection.getY() - doorHeigh, 0);
				doorLeftTop = new Point(rightDoorIntersection.getX(),
						rightDoorIntersection.getY() - doorHeigh, 0);
			}
			Path doorPath = new Path();
			doorPath.moveTo(doorLeftBottom.getX(), doorLeftBottom.getY());
			doorPath.lineTo(doorLeftTop.getX(), doorLeftTop.getY());
			doorPath.lineTo(doorRightTop.getX(), doorRightTop.getY());
			doorPath.lineTo(doorRightBottom.getX(), doorRightBottom.getY());
			doorPath.lineTo(doorLeftBottom.getX(), doorLeftBottom.getY());
			this.canvas.drawPath(doorPath, this.paintWall3DDoor);
		}
		p.lineTo(this.toOnDisplay.getX(), toOnDisplay2.getY());
		p.lineTo(this.toOnDisplay.getX(), this.toOnDisplay.getY() - this.wallHeight);
		p.lineTo(this.fromOnDisplay.getX(), this.fromOnDisplay.getY() - this.wallHeight);
		p.lineTo(this.fromOnDisplay.getX(), this.fromOnDisplay.getY());
		this.canvas.drawPath(p, this.paintWall3DFILL);

	}
}